package com.linjj.seckill.controller;

import com.linjj.seckill.access.AccessLimit;
import com.linjj.seckill.domain.SeckillOrder;
import com.linjj.seckill.domain.User;
import com.linjj.seckill.rabbitmq.MessageSender;
import com.linjj.seckill.rabbitmq.SeckillMessage;
import com.linjj.seckill.redis.GoodsKey;
import com.linjj.seckill.redis.RedisService;
import com.linjj.seckill.service.IGoodsService;
import com.linjj.seckill.service.IOrderService;
import com.linjj.seckill.service.ISeckillService;
import com.linjj.seckill.vo.CodeMsg;
import com.linjj.seckill.vo.Result;
import com.linjj.seckill.vo.SeckillGoodsVo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
/**
 * 秒杀控制器
 * */
@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {
    @Autowired
    private RedisService redisService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISeckillService seckillService;
    @Autowired
    private MessageSender messageSender;
    /**
     * 结束秒杀标志，减少对redis的访问
     * */
    private HashMap<Long, Boolean> localOverMap =  new HashMap<Long, Boolean>();
    /**
     * 初始化
     * 初始化结束秒杀标志
     * 加载商品库存到redis
     * */
    @Override
    public void afterPropertiesSet() throws Exception {
        List <SeckillGoodsVo> seckillGoodsVoList =  goodsService.seckillList();
        for(SeckillGoodsVo seckillGoodsVo : seckillGoodsVoList){
            redisService.set(GoodsKey.seckillGoodsStockPrefix,""+seckillGoodsVo.getId(),seckillGoodsVo.getSeckillStock());
            localOverMap.put(seckillGoodsVo.getId(),false);
        }
    }

    /**
     * 获取验证码
     * */
    @AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
    @GetMapping("/verifyCode")
    @ResponseBody
    public Result<String> getSeckillVerifyCod(HttpServletResponse response, User user,@RequestParam("goodsId")long goodsId) {
        try {
            BufferedImage image  = seckillService.createVerifyCode(user, goodsId);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "JPEG", out);
            out.flush();
            out.close();
            return null;
        }catch(Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.SERVER_ERROR);
        }
    }

    /**
     * 秒杀接口
     * redis预减缓存
     * 重复秒杀判断
     * 入队
     * */
    @AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
    @PostMapping("/do_seckill")
    @ResponseBody
    public Result seckill(User user,String address,
                          @RequestParam(value="goodsId") long goodsId,
                          @RequestParam(value="verifyCode", defaultValue="0")int verifyCode){

        /**
         * 验证码校验
         * */
        boolean check = seckillService.checkVerifyCode(user, goodsId, verifyCode);
        if(!check) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }

        /**
         * 该商品是否秒杀结束
         * */
        boolean seckillover = localOverMap.get(goodsId);
        if(seckillover){
            return Result.error(CodeMsg.SECKILL_OVER); //秒杀结束
        }

        /**
         *是否重复秒杀
         * */
        SeckillOrder seckillOrder = orderService.getSeckillOrderByUserIdAndGoodsId(user.getUserId(),goodsId);
        if(seckillOrder!=null){
            return Result.error(CodeMsg.REPEATE_MIAOSHA);//重复秒杀
        }

        /**
         * Redis预减库存
         * */
        long seckillStock = redisService.decr(GoodsKey.seckillGoodsStockPrefix,""+goodsId);
        if(seckillStock<0){
            localOverMap.put(goodsId,true);
            return Result.error(CodeMsg.SECKILL_OVER);//库存不足，秒杀结束
        }

        /**
         * RabbitMQ入队
         * */
        SeckillMessage seckillMessage = new SeckillMessage(user,goodsId,address);
        messageSender.sendSeckillMessage(seckillMessage);
        return Result.success(0);
    }

    /**
     * 查询秒杀结果接口
     * orderId：成功
     * -1：秒杀失败
     * 0： 排队中
     * */
    @AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
    @GetMapping("/result")
    @ResponseBody
    public Result<Long> seckillReslut(User user ,long goodsId) {
        long result  =seckillService.getSeckillResult(user.getUserId(), goodsId);
        return Result.success(result);
    }

}
